#------------------------------------------------------------------------------ # The following functions are made available to get a random number or values # based on a specific type of distribution. The majority of the code has been # taken and adapted as individual functions from the ADOxx.org site or more # specifically: https://www.adoxx.org/live/faq/-/message_boards/message/225370 # although for most of them other sources have been consulted as well. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ FUNCTION func_tryValue:global input:string # This function tries to transform the provided input into a numeric value # (integer or real). Note that it has one major difference to lam_tryValue: # the parameter MUST be a string. It is unfortunately not possible to overload # the function for other parameters. If the type of input is not a string or is # unknown, then use lam_tryValue. #------------------------------------------------------------------------------ return:(cond(regex("^([0-9]+(\\.[0-9]*)?)[ ]*$", input), VAL input, regex("^([0-9]+(\\,[0-9]*)?)[ ]*$", input), VAL (replace(input, ",", ".")), input)) #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ FUNCTION randomStandardUniformDist:global # Creates a random number for a uniform distribution between (incl.) 0.0 and # (excl.) 1.0. So it is not exactly "standard Uniform", but close, maybe even # more useful, since it allows to avoid problematic results (e.g. ln(U) --> # fails if U = 0). #------------------------------------------------------------------------------ return:(random()) # We assume that random() is uniformly distributed. (We have to believe in something). #------------------------------------------------------------------------------ FUNCTION randomUniformDist:global rea_lowlimit:real rea_uplimit:real # Creates a random number for a uniform distribution between (incl.) lower # limit and (excl.) upper limit. #------------------------------------------------------------------------------ return:((randomStandardUniformDist()*(rea_uplimit-rea_lowlimit))+rea_lowlimit) #------------------------------------------------------------------------------ FUNCTION randomStandardNormalDist:global # Creates a random number for a standard normal distribution (mu=0, sigma=1) # using the Box-Muller. Not entirely sure yet if it should be "log" or "ln". # "Efficient sampling from truncated bivariate Gaussians via Box-Muller # transformation" uses "ln", but the source they cite and "A note on the # generation of random normal deviates" (by Box and Muller) uses "log". It # seems that using log provides results closer to the expected value (0), # which does however also look like it distorts the standard deviation, so we # use ln instead (NOTE: ln in AdoScript is log, log in AdoScript is log10). #------------------------------------------------------------------------------ return:(sqrt(-2.0*log(1.0-randomStandardUniformDist()))*cos(2*3.14159265*randomStandardUniformDist())) #------------------------------------------------------------------------------ FUNCTION randomNormalDist:global rea_expectancy:real rea_stddev:real # Creates a random number for a normal distribution with a specific # expectancy value and standard deviation. It is based on the standard normal # deviation, whose result can simply be adapted by multiplying with the # standard deviation and adding the expectancy value. #------------------------------------------------------------------------------ return:((randomStandardNormalDist()*rea_stddev)+rea_expectancy) #------------------------------------------------------------------------------ FUNCTION randomTriangularDist:global rea_lowlimit:real rea_mode:real rea_uplimit:real # Creates a random number for a triangular distribution. The implementation is # based on "Beyond Beta - Other Continuous Families of Distributions with # Bounded Support and Applications". #------------------------------------------------------------------------------ return:(set(rea_rand, randomStandardUniformDist()), cond(rea_rand<((rea_mode-rea_lowlimit)/(rea_uplimit-rea_lowlimit)), rea_lowlimit+sqrt(rea_rand*(rea_mode-rea_lowlimit)*(rea_uplimit-rea_lowlimit)), rea_uplimit-sqrt((1-rea_rand)*(rea_uplimit-rea_mode)*(rea_uplimit-rea_lowlimit)))) #------------------------------------------------------------------------------ FUNCTION randomExponentialDist:global rea_scale:real # Creates a random number for an exponential distribution with a specific # inverse scale. It uses the inverse CDF to create the random number. #------------------------------------------------------------------------------ return:((-log(1-randomStandardUniformDist()))/rea_scale) #------------------------------------------------------------------------------ FUNCTION randomDiscreteDistPositions:global arr_probabilites:array # Creates a random number for a discrete distribution, where each possibility # has a specific probability. The possible values are the positions of the # array (i.e. from 0 to its Length-1). The probabilities should be real numbers # specified in the array. The function returns the position of the array that # has been chosen. The sum of all the probabilities MUST be 1.0. # You can directly instantiate an array using: {0.4, 0.2, 0.2, 0.1, 0.1} # Note: The implementation relies on a for-loop and returns as soon as it found # the proper value. It might help to sort the array according to the # probabilities in descending order (largest first) to execute quicker in most # of the cases. #------------------------------------------------------------------------------ return:(set(rea_random, randomStandardUniformDist()), set(rea_probsum, 0.0), set(int_pos, 0), while(((rea_random>=rea_probsum) AND (int_pos<(LEN arr_probabilites))), (set(rea_probsum, rea_probsum+arr_probabilites[int_pos]), set(int_pos, int_pos+1)), int_pos-1)) # the (int_pos=rea_probsum) AND (int_pos<(LEN map_probabilites))), (set(rea_probsum, rea_probsum+(VAL token(token(str_map, int_pos, ","), 1, ":").trim())), set(int_pos, int_pos+1)), token(token(str_map, int_pos-1, ","), 0, ":").trim())), cond(search(str_res, "\"", 0)=0, copy(str_res, 1, LEN str_res-2), func_tryValue(str_res))) #------------------------------------------------------------------------------ FUNCTION randomDiscreteUniformDist:global int_lowlimit:integer int_uplimit:integer # Returns a random value from a discrete uniform distribution of integers # between (incl.) lower limit and (excl.) upper limit. #------------------------------------------------------------------------------ return:(INT randomUniformDist(int_lowlimit, int_uplimit)) #------------------------------------------------------------------------------ FUNCTION randomBernoulliDist:global rea_prob:real # Returns either 1 or 0 based on the Bernoulli distribution. The provided # probability is used for the value 1, while its inverse (1-probability) is # used for the value 0. #------------------------------------------------------------------------------ return:(cond(randomStandardUniformDist()